package com.hzw.code.vm

import com.hzw.code.net.IResource
import com.hzw.code.net.exception.ResourceException

/**
 *
 * @Author:         HuaZhongWei
 * @CreateDate:     2020/4/18 4:10 PM
 *
 * @Description:    数据仓库顶层类
 *
 */
abstract class AbsRepository {

    /**
     * 优先获取远程数据。
     * 如果远程数据拉取成功，则根据条件是否保存远程数据，并返回
     * 如果远程数据拉取未成功，则加载本地数据，如果本地数据为空，直接抛出远程拉取失败的异常
     *
     *
     * @param remote 远程数据源
     * @param local 本地数据源
     * @param save 保存数据到本地
     * @param isSave 是否保存数据到本地，默认 true
     */
    suspend fun <T> fetchRemoteWithLocal(
        remote: suspend () -> IResource<T>,
        local: suspend () -> T?,
        save: suspend (T) -> Unit,
        isSave: (T) -> Boolean = { true }
    ):T {
        val remoteResource = remote.invoke()
        return if (remoteResource.isSuccess()) {
            val data = remoteResource.data()
            if (isSave(data)) {
                save(data)
            }
            data
        } else {
            local.invoke() ?: throw ResourceException(remoteResource)
        }
    }

    /**
     * 优先使用本地数据
     * 根据条件判断判断，是否使用本地数据：如果是，直接返回，否则执行远程拉取
     * 远程拉取成功，则根据条件判读是否保存，默认保存
     * 远程拉取失败，直接抛出异常
     *
     * @param local 本地数据源
     * @param remote 远程数据源
     * @param save 保存数据到本地
     * @param isUseLocal 是否直接使用本地数据，默认本地数据不为空的时候为 true
     * @param isSave 是否保存数据到本地，默认 true
     *
     */
    suspend fun <T> loadLocalWithRemote(
        local: suspend () -> T?,
        remote: suspend () -> IResource<T>,
        save: suspend (T) -> Unit,
        isUseLocal: (T?) -> Boolean = { it != null },
        isSave: (T) -> Boolean = { true }
    ): T {
        val localData = local.invoke()
        if (isUseLocal(localData)) {
            return localData!!
        } else {
            val remoteResource =  remote.invoke()
            if (remoteResource.isSuccess()) {
                if (isSave(remoteResource.data())) {
                    save(remoteResource.data())
                }
                return remoteResource.data()
            }
            throw ResourceException(remoteResource)
        }
    }

    /**
     * 清除
     */
    fun onClear() {

    }
}